package services;

import java.util.Calendar;
import java.util.Collection;
import java.util.Date;

import javax.transaction.Transactional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import repositories.CuotaRepository;
import domain.Administrador;
import domain.ComunidadDeVecinos;
import domain.Cuota;
import domain.Vecino;

@Service
@Transactional
public class CuotaService {

	// Managed Repository
	@Autowired
	private CuotaRepository cuotaRepository;
	@Autowired
	private AdministradorService administradorService;

	// Supporting Services
	@Autowired
	private VecinoService vecinoService;
	@Autowired
	private ComunidadDeVecinosService comunidadDeVecinosService;

	// Constructors
	public CuotaService() {
		super();
	}

	// Simple CRUD methods
	public Cuota findOne(int cuotaId) {
		Cuota result;

		result = cuotaRepository.findOne(cuotaId);

		return result;
	}

	public Cuota create(Vecino v, ComunidadDeVecinos cv) {
		Assert.notNull(v);
		Assert.notNull(cv);
		Cuota res;
		Date currentMoment;

		currentMoment = new Date(System.currentTimeMillis()-1000);

		res = new Cuota();

		res.setVecino(v);
		res.setComunidadDeVecinos(cv);
		res.setEstado("No pagada");
		res.setTipo("Ordinaria");
		res.setFecha(currentMoment);
		res.setImporte(cv.getImporteCuota());

		return res;
	}

	private Cuota createExtraordinaria(Vecino v, ComunidadDeVecinos cv,
			Double importe) {
		Assert.notNull(v);
		Assert.notNull(cv);
		Assert.notNull(importe);

		Cuota res;
		Date currentMoment;

		currentMoment = new Date(System.currentTimeMillis()-1000);

		res = new Cuota();

		res.setVecino(v);
		res.setComunidadDeVecinos(cv);
		res.setEstado("No pagada");
		res.setTipo("Extraordinaria");
		res.setFecha(currentMoment);
		res.setImporte(importe);

		return res;
	}

	public Cuota save(Cuota cuota) {
		Assert.notNull(cuota);
		Assert.isTrue(cuota.getFecha().before(new Date()));
		Assert.isTrue(cuota.getEstado().equals("Pagada")
				|| cuota.getEstado().equals("No pagada")
				|| cuota.getEstado().equals("Pendiente"));
		Cuota res;

		if (cuota.getId() == 0) {
			if (!cuota.getTipo().equals("Extraordinaria")) {
				Administrador principal;
				principal = administradorService.findByPrincipal();
				Assert.isTrue(principal instanceof Administrador);
			}

		} else {
			Vecino principal;
			principal = vecinoService.findByPrincipal();
			Assert.isTrue(cuota.getVecino().equals(principal));
		}
		res = cuotaRepository.save(cuota);

		return res;
	}

	// Other Business methods
	
	public Collection<Cuota> findCuotasExtraordinariasByComunidadAdministrador(
			int comunidadId) {
		Collection<Cuota> res;
		Administrador principal;
		principal = administradorService.findByPrincipal();
		Assert.isTrue(principal instanceof Administrador);

		res = cuotaRepository
				.findCuotasExtraordinariaByComunidadDeVecinos(comunidadId);

		return res;
	}

	public Collection<Cuota> findCuotasExtraordinariaByComunidadDeVecinosAndByPresidente(
			int comunidadDeVecinosId) {
		Collection<Cuota> result;
		ComunidadDeVecinos comunidad;
		Vecino principal;
		Vecino presidente;

		comunidad = comunidadDeVecinosService.findOne(comunidadDeVecinosId);

		principal = vecinoService.findByPrincipal();
		presidente = comunidad.getPresidente();

		Assert.isTrue(principal.equals(presidente));

		result = cuotaRepository
				.findCuotasExtraordinariaByComunidadDeVecinos(comunidadDeVecinosId);

		return result;
	}

	public Collection<Cuota> findCuotasByVecino() {
		Collection<Cuota> result;
		Vecino principal;

		principal = vecinoService.findByPrincipal();
		Assert.isTrue(principal instanceof Vecino);
		result = cuotaRepository.findCuotasByVecino(principal.getId());
		return result;
	}

	public Collection<Cuota> findCuotasNoPagadasByVecino() {
		Collection<Cuota> result;
		Vecino principal;

		principal = vecinoService.findByPrincipal();
		Assert.isTrue(principal instanceof Vecino);
		result = cuotaRepository.findCuotasNoPagadasByVecino(principal.getId());
		return result;
	}

	public Collection<Cuota> findCuotasNoPagadasByAdmin(int vecinoId) {
		Collection<Cuota> result;
		Administrador principal;
		principal = administradorService.findByPrincipal();
		Assert.isTrue(principal instanceof Administrador);

		result = cuotaRepository.findCuotasNoPagadasByVecino(vecinoId);
		return result;
	}

	public void pagarCuota(int cuotaId) {
		Cuota cuota;
		Vecino principal;
		double fondoAnterior;
		double fondoActual;

		cuota = findOne(cuotaId);

		Assert.notNull(cuota);

		fondoAnterior = cuota.getComunidadDeVecinos().getFondo();

		Assert.isTrue(cuota.getEstado().equals("No pagada"));

		principal = vecinoService.findByPrincipal();
		Assert.isTrue(principal instanceof Vecino);
		Assert.isTrue(cuota.getVecino().equals(principal));

		cuota.setEstado("Pagada");

		fondoActual = fondoAnterior + cuota.getImporte();

		cuota.getComunidadDeVecinos().setFondo(fondoActual);
		save(cuota);

	}

	public Collection<Cuota> findCuotasByComunidadDeVecinosAdministrador(
			int comunidadDeVecinosId) {
		Collection<Cuota> res;
		Administrador principal;
		principal = administradorService.findByPrincipal();
		Assert.isTrue(principal instanceof Administrador);
		res = cuotaRepository
				.findCuotasByComunidadDeVecinos(comunidadDeVecinosId);
		return res;
	}
	
	public Collection<Cuota> findCuotasByComunidadDeVecinosPresidente(
			int comunidadDeVecinosId) {
		Collection<Cuota> res;
		Vecino principal;
		Vecino presidente;
		ComunidadDeVecinos comunidad;
		
		comunidad = comunidadDeVecinosService.findOne(comunidadDeVecinosId);
		presidente = comunidad.getPresidente();
		principal = vecinoService.findByPrincipal();
		
		Assert.isTrue(principal.equals(presidente));
		
		Assert.isTrue(principal instanceof Vecino);
		res = cuotaRepository
				.findCuotasByComunidadDeVecinos(comunidadDeVecinosId);
		return res;
	}

	public Collection<Cuota> findCuotasNoPagadasByComunidadAdministrador(int comunidadId) {
		Collection<Cuota> res;
		Administrador principal;
		principal = administradorService.findByPrincipal();
		Assert.isTrue(principal instanceof Administrador);

		res = cuotaRepository
				.findCuotasNoPagadasByComunidadDeVecinos(comunidadId);

		return res;
	}

	public Collection<Cuota> findCuotasNoPagadasByComunidadPresidente(int comunidadId) {
		Collection<Cuota> res;
		Vecino principal;
		Vecino presidente;
		ComunidadDeVecinos comunidad;
		
		comunidad = comunidadDeVecinosService.findOne(comunidadId);
		principal = vecinoService.findByPrincipal();
		Assert.isTrue(principal instanceof Vecino);
		
		presidente = comunidad.getPresidente();

		Assert.isTrue(principal.equals(presidente));

		res = cuotaRepository
				.findCuotasNoPagadasByComunidadDeVecinos(comunidadId);

		return res;
	}
	
	
	public Collection<Cuota> findCuotasOrdinariasByComunidadPresidente(int comunidadId) {
		Collection<Cuota> res;
		Vecino principal;
		Vecino presidente;
		ComunidadDeVecinos comunidad;
		
		comunidad = comunidadDeVecinosService.findOne(comunidadId);
		presidente = comunidad.getPresidente();
		principal = vecinoService.findByPrincipal();
		
		Assert.isTrue(principal.equals(presidente));
		
		Assert.isTrue(principal instanceof Vecino);
		res = cuotaRepository
				.findCuotasOrdinariasByComunidadDeVecinos(comunidadId);
		return res;
	}

	public Collection<Cuota> findCuotasOrdinariasByComunidadAdministrador(int comunidadId) {
		Collection<Cuota> res;
		Administrador principal;
		principal = administradorService.findByPrincipal();
		Assert.isTrue(principal instanceof Administrador);

		res = cuotaRepository
				.findCuotasOrdinariasByComunidadDeVecinos(comunidadId);

		return res;
	}

	

	public Collection<Cuota> findCuotasNoPagadasByVecinoYComunidad(
			int morosoId, int comunidadId) {
		Collection<Cuota> result;

		result = cuotaRepository.findCuotasNoPagadasByVecinoYComunidad(
				morosoId, comunidadId);
		return result;
	}

	public void generateFees(int comunidadId) {
		ComunidadDeVecinos cv;
		Collection<Vecino> vecinos;
		Assert.isTrue(haPasado1mesDesdeCuotaOrdinaria(comunidadId));
		cv = comunidadDeVecinosService.findOne(comunidadId);
		vecinos = cv.getVecinos();

		for (Vecino v : vecinos) {
			Cuota c;
			c = create(v, cv);
			save(c);
		}
		
	}

	public boolean haPasado1mesDesdeCuotaOrdinaria(int comunidadId) {
		boolean res;
		res = true;
		Collection<Date> fechaUltimasCuotasOrdinarias;
		Date fechaActual;

		fechaActual = new Date();
		fechaUltimasCuotasOrdinarias = cuotaRepository
				.findFechaUltimaCuotaOrdinariaByComunidad(comunidadId);

		for (Date d : fechaUltimasCuotasOrdinarias) {
			Date fechaMinima;
			Calendar calendar = Calendar.getInstance();
			calendar.setTime(d);
			calendar.add(Calendar.MONTH, +1);
			fechaMinima = calendar.getTime();

			if (fechaActual.before(fechaMinima)) {
				res = false;
			}
		}
		return res;

	}

	public void generarCuotaExtraOrdinaria(int comunidadId, Double importe) {
		ComunidadDeVecinos cv;
		Collection<Vecino> vecinos;

		cv = comunidadDeVecinosService.findOne(comunidadId);
		vecinos = cv.getVecinos();

		for (Vecino v : vecinos) {
			Cuota c;
			c = createExtraordinaria(v, cv, importe);
			save(c);
		}

	}

	public void delete(Cuota c) {
		Assert.notNull(c);
		cuotaRepository.delete(c);
		
	}

}
